﻿using DesertKharonIrcPlugin.Emotes;
using DesertKharonIrcPlugin.Emotes.Twitch;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace DesertKharonIrcPlugin
{
    public class FontRenderer : IDisposable
    {
        private bool _updateValues = true;

        private SolidBrush _fontBrush;
        private Font _font;
        private Color _fontColor = Color.White;
        private Color _originalFontColor = Color.White;

        private bool _updateOutlinePen = true;
        private Pen _outlinePen;
        private bool _drawOutline = false;
        private Color _outlineColor = Color.Black;
        private Color _originalOutlineColor = Color.Black;

        private int _outlineThickness = 2;

        private Color _originalBackgroundColor = Color.Transparent;
        private Color _backgroundColor = Color.Transparent;

        private float _opacity = 1f;

        private StringFormat _stringFormat = StringFormat.GenericDefault;

        public float Opacity
        {
            get { return _opacity; }
            set
            {
                if (value > 1f)
                    _opacity = 1f;
                else if (value < 0f)
                    _opacity = 0f;
                else
                    _opacity = value;

                _fontColor = Color.FromArgb((int)(_opacity * ((float)_originalFontColor.A / 255f) * 255f), _originalFontColor);
                _outlineColor = Color.FromArgb((int)(_opacity * ((float)_originalOutlineColor.A / 255f) * 255f), _originalOutlineColor);
                _backgroundColor = Color.FromArgb((int)(_opacity * ((float)_originalBackgroundColor.A / 255f) * 255f), _originalBackgroundColor);
            }
        }

        public Font Font
        {
            get { return _font; }
            set { _font = value; }
        }

        public Color FontColor
        {
            get { return _originalFontColor; }
            set 
            { 
                _originalFontColor = value;
                _fontColor = Color.FromArgb((int)(_opacity * ((float)_originalFontColor.A / 255f) * 255f), _originalFontColor);
            }
        }

        public Color OutlineColor
        {
            get { return _originalOutlineColor; }
            set 
            { 
                _originalOutlineColor = value;
                _outlineColor = Color.FromArgb((int)(_opacity * ((float)_originalOutlineColor.A / 255f) * 255f), _originalOutlineColor);
            }
        }

        public Color BackgroundColor
        {
            get { return _originalBackgroundColor; }
            set
            {
                _originalBackgroundColor = value;
                _backgroundColor = Color.FromArgb((int)(_opacity * ((float)_originalBackgroundColor.A / 255f) * 255f), _originalBackgroundColor);
            }
        }

        public int OutlineThickness
        {
            get { return _outlineThickness; }
            set { _outlineThickness = value; }
        }

        public bool DrawOutline
        {
            get { return _drawOutline; }
            set { _drawOutline = value; }
        }

        public FontRenderer(Font font)
        {
            _font = font;
            _fontBrush = new SolidBrush(_fontColor);
            _outlinePen = new Pen(_outlineColor, _outlineThickness);
            _outlinePen.LineJoin = LineJoin.Round;
        }

        public Bitmap Draw(string text)
        {
            return DoDraw(text, _fontColor, _outlineColor);
        }

        public Bitmap Draw(string text, Color fontColor)
        {
            return DoDraw(text,
                Color.FromArgb((int)(_opacity * ((float)fontColor.A / 255f) * 255f), fontColor),
                _outlineColor);
        }

        public Bitmap Draw(string text, Color fontColor, Color outlineColor)
        {
            return DoDraw(text, 
                Color.FromArgb((int)(_opacity * ((float)fontColor.A / 255f) * 255f), fontColor),
                Color.FromArgb((int)(_opacity * ((float)outlineColor.A / 255f) * 255f), outlineColor));
        }

        private Bitmap DoDraw(string text, Color fontColor, Color outlineColor)
        {
            SizeF bitmapSize = text.Measure(_font);
            Bitmap bitmap = new Bitmap((int)Math.Ceiling(bitmapSize.Width), (int)Math.Ceiling(bitmapSize.Height));            

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(_backgroundColor);

                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                _fontBrush.Color = fontColor;
                if (_drawOutline)
                {
                    _outlinePen.Color = outlineColor;
                    _outlinePen.Width = _outlineThickness;
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddString(text, _font.FontFamily, (int)_font.Style, graphics.DpiY * _font.Size / 72f, PointF.Empty, _stringFormat);

                        graphics.DrawPath(_outlinePen, path);
                        graphics.FillPath(_fontBrush, path);
                    }
                }
                else
                    graphics.DrawString(text, _font, _fontBrush, 0f, 0f, _stringFormat);
            }

            return bitmap;
        }

        public void Dispose()
        {
            if (_fontBrush != null)
            {
                _fontBrush.Dispose();
                _fontBrush = null;
            }

            if (_outlinePen != null)
            {
                _outlinePen.Dispose();
                _outlinePen = null;
            }
        }
    }
}
